package interpreter;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

public class TwoParameterVariation {
	static Map<String,Boolean> explored = new HashMap<String,Boolean>();
	
	private static String getCode(int []params, int firstIndex, int secondIndex) {
		String code = firstIndex + "_" + secondIndex + "_";
		for(int i=0; i<params.length; i++) {
			code += RealResult.params_codes[i] + "_" + params[i];
		}
		return code;
	}
	
	public static String plotVeryInterestingResults(String folder, int []params, int firstIndex, int secondIndex, ArrayList<RealResult> realResults) {
		String gnuPlotScript = "";
		String code = getCode(params, firstIndex, secondIndex);
		if(explored.containsKey(code)) {
			// Skip this configuration if it was already explored
			return "";
		}
		// Mark current configuration as explored
		explored.put(code, true);
		
		// Look for all other matching results
		ArrayList<RealResult> matching = new ArrayList<RealResult>();
		for(RealResult r : realResults) {
			if(r.matches(params)) {
				matching.add(r);
			}
		}
		
		if(matching.size() > 1) {
			// Save distinct values for first
			Map<Integer,Boolean> used_first = new HashMap<Integer, Boolean>();
			for(int i=0; i<matching.size(); i++) {
				used_first.put(matching.get(i).params[firstIndex], true);
			}
			
			// Save distinct values for second
			Map<Integer,Boolean> used_second = new HashMap<Integer, Boolean>();
			for(int i=0; i<matching.size(); i++) {
				used_second.put(matching.get(i).params[secondIndex], true);
			}
			
			if(used_first.size() > 1 && used_second.size() > 1) {
				// Save the actual distinct values
				
				int []first_vals = new int[used_first.size()];
				int []second_vals = new int[used_second.size()];
				
				int i1 = 0;
				for(Entry<Integer,Boolean> e : used_first.entrySet()) {
					first_vals[i1++] = e.getKey();
				}
				
				int i2 = 0;
				for(Entry<Integer,Boolean> e : used_second.entrySet()) {
					second_vals[i2++] = e.getKey();
				}
				
				// Sort the distinct values
				Arrays.sort(first_vals);
				Arrays.sort(second_vals);
				
				// Get the position based on the value
				Map<Integer,Integer> firstpos = new HashMap<Integer, Integer>();
				Map<Integer,Integer> secondpos = new HashMap<Integer, Integer>();
				for(int i=0; i<first_vals.length; i++) {
					firstpos.put(first_vals[i], i);
				}
				for(int i=0; i<second_vals.length; i++) {
					secondpos.put(second_vals[i], i);
				}
				
				boolean [][]VALUES_KNOWN = new boolean[first_vals.length][second_vals.length];
				
				double [][]T = new double[first_vals.length][second_vals.length];
				double [][]Tstd = new double[first_vals.length][second_vals.length];
				double [][]Tlow = new double[first_vals.length][second_vals.length];
				double [][]Thigh = new double[first_vals.length][second_vals.length];
				
				double [][]ART = new double[first_vals.length][second_vals.length];
				double [][]ARTstd = new double[first_vals.length][second_vals.length];
				double [][]ARTlow = new double[first_vals.length][second_vals.length];
				double [][]ARThigh = new double[first_vals.length][second_vals.length];
				
				double [][]MRT = new double[first_vals.length][second_vals.length];
				double [][]MRTstd = new double[first_vals.length][second_vals.length];
				double [][]MRTlow = new double[first_vals.length][second_vals.length];
				double [][]MRThigh = new double[first_vals.length][second_vals.length];
				
				// Reset all results
				for(i1=0; i1<first_vals.length; i1++) {
					for(i2=0; i2<second_vals.length; i2++) {
						T[i1][i2] = 0;
						Tstd[i1][i2] = 0;
						ART[i1][i2] = 0;
						ARTstd[i1][i2] = 0;
						MRT[i1][i2] = 0;
						MRTstd[i1][i2] = 0;
						VALUES_KNOWN[i1][i2] = false;
					}
				}
				
				// Fill up the table with the actual results
				for(int i=0; i<matching.size(); i++) {
					int pos1=0, pos2=0;
					pos1 = firstpos.get(matching.get(i).params[firstIndex]);
					pos2 = secondpos.get(matching.get(i).params[secondIndex]);
					
					T[pos1][pos2] = matching.get(i).Tmean;
					Tstd[pos1][pos2] = matching.get(i).TstdDev;
					Tlow[pos1][pos2] = matching.get(i).confidence1Tmin;
					Thigh[pos1][pos2] = matching.get(i).confidence1Tmax;
					ART[pos1][pos2] = matching.get(i).ARTmean;
					ARTstd[pos1][pos2] = matching.get(i).ARTstdDev;
					ARTlow[pos1][pos2] = matching.get(i).confidence1ARTmin;
					ARThigh[pos1][pos2] = matching.get(i).confidence1ARTmax;
					MRT[pos1][pos2] = matching.get(i).MRTmean;
					MRTstd[pos1][pos2] = matching.get(i).MRTstdDev;
					MRTlow[pos1][pos2] = matching.get(i).confidence1MRTmin;
					MRThigh[pos1][pos2] = matching.get(i).confidence1MRTmax;
					
					VALUES_KNOWN[pos1][pos2] = true;
				}
				
				int numberOfConnectionsInGraph = 0;
				for(i2=0; i2<second_vals.length; i2++) {
					int hits = 0;
					for(i1=0; i1<first_vals.length; i1++) {
						if(VALUES_KNOWN[i1][i2]) {
							hits ++;
						}
					}
					numberOfConnectionsInGraph += hits-1;
				}
				
				if(numberOfConnectionsInGraph >= 2) {
					// Construct the filename
					String importantParts = "two_" + firstIndex + "_" + secondIndex;
					for(int i=0; i<params.length; i++) {
						importantParts += "_" + RealResult.params_codes[i];
						if(params[i] == 0) {
							importantParts += "xx";
						} else {
							importantParts += params[i];
						}
					}
					
					// txt filename
					String txtFilename = importantParts + ".txt";
					String txtPath = folder + (folder.endsWith("/") ? txtFilename : "/" + txtFilename);
					System.err.println("VERY MATCHING FILENAME: " + txtPath);
					try {
						FileWriter fstream = new FileWriter(txtPath, false);
						BufferedWriter outFile = new BufferedWriter(fstream);
	
						// A non-existing combination
						String emptyLine = ",,,,,,,,,,,,";
						for(i1=0; i1<first_vals.length; i1++) {
							outFile.write("" + first_vals[i1]);
							for(i2=0; i2<second_vals.length; i2++) {
								if(VALUES_KNOWN[i1][i2]) {
									outFile.write(
									"," + String.format("%.3f",T[i1][i2]) + "," + String.format("%.3f",Tstd[i1][i2]) +
									"," + String.format("%.3f",Tlow[i1][i2]) + "," + String.format("%.3f",Thigh[i1][i2]) +
									"," + String.format("%.3f",ART[i1][i2]) + "," + String.format("%.3f",ARTstd[i1][i2]) +
									"," + String.format("%.3f",ARTlow[i1][i2]) + "," + String.format("%.3f",ARThigh[i1][i2]) +
									"," + String.format("%.3f",MRT[i1][i2]) + "," + String.format("%.3f",MRTstd[i1][i2]) +
									"," + String.format("%.3f",MRTlow[i1][i2]) + "," + String.format("%.3f",MRThigh[i1][i2])
									);
								} else {
									outFile.write(emptyLine);
								}
							}
							outFile.newLine();
						}
						
						gnuPlotScript += gnuplot(txtFilename, params, firstIndex, first_vals, secondIndex, second_vals);
						
						outFile.close();
					} catch (Exception e) {
						System.out.println("Can't write to experiment file!!!");
						e.printStackTrace();
					}
				}
			}
		}
		return gnuPlotScript;
	}
		
	private static String gnuplot(String txtFileName, int []params, int firstIndex, int[]first_vals, int secondIndex, int[]second_vals) {
		String importantParts = txtFileName.replaceAll("\\.txt", "");
		String title = " - ";
		boolean is_first_in_title = true;
		for(int i=0; i<params.length; i++) {
			if(params[i] != 0) {
				if(!is_first_in_title) {
					title += ", ";
				} else {
					is_first_in_title = false;
				}
				title += RealResult.params_codes[i] + ": " + params[i];
			}
		}
		String xlabel = RealResult.params_names[firstIndex];
		String xrange = "[0:"+(first_vals[first_vals.length-1]+1)+"]";
		String gnuPlotScript = "";
gnuPlotScript +=
"set autoscale\n"+
"unset log\n"+
"unset label\n"+
"set xtic auto\n"+
"set ytic auto\n"+
"set title \"Throughput"+title+"\" font \"Calibri,15\"\n"+
"set xlabel \""+xlabel+"\"\n"+
"set ylabel \"Throughput (q/s)\"\n"+
"set yrange[0:]\n"+
"set xrange"+xrange+"\n"+
"set terminal png\n"+
"set output \""+importantParts+"_Throughput.png\"\n"+
"set datafile separator \",\"\n"+
"\n"+
"set key bottom Left\n";
		boolean is_first = true;
		for(int i2=0; i2<second_vals.length; i2++) {
			if(is_first) {
				gnuPlotScript += "plot ";
				is_first = false;
			}
			int value = second_vals[i2];
			int column = i2 * 12 + 2;
			gnuPlotScript += "\""+txtFileName+"\" using 1:"+column+":"+(column+2)+":"+(column+3)+" title \""+RealResult.params_codes[secondIndex]+"="+value+"\" with yerrorlines";
			if(i2 + 1 < second_vals.length) {
				gnuPlotScript += ",\\\n";
			}
		}
gnuPlotScript += "\n";
gnuPlotScript += "\n";
gnuPlotScript +=
"set autoscale\n"+
"unset log\n"+
"unset label\n"+
"set xtic auto\n"+
"set ytic auto\n"+
"set title \"Average Response Time"+title+"\" font \"Calibri,15\"\n"+
"set xlabel \""+xlabel+"\"\n"+
"set ylabel \"Average Response Time (ms)\"\n"+
"set yrange[0:]\n"+
"set xrange"+xrange+"\n"+
"set terminal png\n"+
"set output \""+importantParts+"_ART.png\"\n"+
"set datafile separator \",\"\n"+
"\n"+
"set key bottom Left\n";
		is_first = true;
		for(int i2=0; i2<second_vals.length; i2++) {
			if(is_first) {
				gnuPlotScript += "plot ";
				is_first = false;
			}
			int value = second_vals[i2];
			int column = i2 * 12 + 6;
			gnuPlotScript += "\""+txtFileName+"\" using 1:"+column+":"+(column+2)+":"+(column+3)+" title \""+RealResult.params_codes[secondIndex]+"="+value+"\" with yerrorlines";
			if(i2 + 1 < second_vals.length) {
				gnuPlotScript += ",\\\n";
			}
		}
gnuPlotScript += "\n";
gnuPlotScript += "\n";
gnuPlotScript +=
"set autoscale\n"+
"unset log\n"+
"unset label\n"+
"set xtic auto\n"+
"set ytic auto\n"+
"set title \"Median Response Time"+title+"\" font \"Calibri,15\"\n"+
"set xlabel \""+xlabel+"\"\n"+
"set ylabel \"Median Response Time (ms)\"\n"+
"set yrange[0:]\n"+
"set xrange"+xrange+"\n"+
"set terminal png\n"+
"set output \""+importantParts+"_MRT.png\"\n"+
"set datafile separator \",\"\n"+
"\n"+
"set key bottom Left\n";
		is_first = true;
		for(int i2=0; i2<second_vals.length; i2++) {
			if(is_first) {
				gnuPlotScript += "plot ";
				is_first = false;
			}
			int value = second_vals[i2];
			int column = i2 * 12 + 10;
			gnuPlotScript += "\""+txtFileName+"\" using 1:"+column+":"+(column+2)+":"+(column+3)+" title \""+RealResult.params_codes[secondIndex]+"="+value+"\" with yerrorlines";
			if(i2 + 1 < second_vals.length) {
				gnuPlotScript += ",\\\n";
			}
		}
		gnuPlotScript += "\n";
		gnuPlotScript += "\n";
		return gnuPlotScript;
	}
}
